// -*- C++ -*-
#include <stdexcept>
#include <services/StateService/StateService.hh>
#include "StateManager.h"

// stateをひとつ追加する
void StateManager::addState(const StatePtr state)
{
    StateItr it = m_states.find(state->name());
    if (it != m_states.end()){
        removeState(state->name());
    }
    m_states.insert(StatePair(state->name(), state));
    m_is_updated = true;
}

// stateをStateProfileListから
void StateManager::addStates(const RTMEUS::StateProfileList &profs)
{ 
    for(CORBA::ULong i(0); i < profs.length(); i++){
        addState(StateBase::create(profs[i]));
    }
}
//stateを複数まとめて追加する
void StateManager::addStates(std::vector<StatePtr> &states)
{
    for(unsigned int i=0; i < states.size(); i++){
        addState(states[i]);
    }
}
// stateをひとつ削除する
void StateManager::removeState(const std::string &name)
{
    // find
    StateItr it = m_states.find(name);
    if (it != m_states.end())
    {
        m_states.erase(it);
    }
    m_is_updated = true;
}
// stateを複数まとめて削除する
void StateManager::removeStates(std::vector<std::string> &names)
{
    for(unsigned int i=0; i < names.size(); i++)
    {
        removeState(names[i]);
    }
}

// 自分が管理しているstateを全部削除する
void StateManager::clear()
{
    std::vector<std::string> names = getStateNames();
    // virtualなremoveStateを呼んで欲しいので
    // m_states.clear()とかは使わない
    for(unsigned int i=0; i < names.size(); i++) {
        removeState(names[i]);
    }
}
// 自分が管理している名前一覧を返す
std::vector<std::string> StateManager::getStateNames()
{
    std::vector<std::string> names;
    names.reserve(m_states.size());
    for(StateItr it = m_states.begin(); it != m_states.end(); it++){
        names.push_back(it->first);
    }
    return names;
}

// Stateを一個得る
StatePtr &StateManager::getState(const char *name)
{
    StateItr it = m_states.find(name);
    if (it == m_states.end()){
        throw EInvalidState(name);
    }
    return it->second;
}

// 登録されているStateを全部返す
std::vector<StatePtr> StateManager::getStates()
{
    std::vector<StatePtr> states;
    std::vector<std::string> names = getStateNames();
    for(unsigned int i = 0; i < names.size(); i++)
    {
        states.push_back(getState(names[i].c_str()));
    }
    return states;
}

void StateManager::copyToState(const char *name, RTMEUS::State &state)
{
    // find
    StatePtr &st = getState(name);
    state.name = CORBA::string_dup(name);
    state.data <<= st; // コピー
}

void StateManager::copyToStateList(RTMEUS::StateList &states)
{
    states.length(m_states.size());
    StateItr it;
    CORBA::ULong i;
    for(i= 0,it = m_states.begin(); it != m_states.end(); it++,i++) {
        states[i].name = CORBA::string_dup(it->first.c_str());
        states[i].data <<= it->second; // anyからキャスト，コピー
    }
}

void StateManager::copyToStateSet(RTMEUS::StateSet &states)
{
    copyToStateList(states.datalist);
    states.profile_updated = m_is_updated;
    m_is_updated = false;
}

// Stateを一個セットする
bool StateManager::copyFromState(const RTMEUS::State &state)
{
    try {
        StatePtr &s = getState(state.name);
        return(state.data >>= s); // 配る
    }
    catch (...){
    }
    return false;
}

void StateManager::copyFromStateList(const RTMEUS::StateList &states)
{
  CORBA::ULong i;
  std::string name;
  for(i= 0;i < states.length();i++){
      if (!copyFromState(states[i]))
      {
          name = states[i].name;
          // 型チェックがおかしかったが、ここでエラーを投げてはいけない。
          // なぜなら、H8だとたまにコピーは失敗することがあるみたいなので。
          //throw EBindError(name);
      }
  }
}

// CORBAのStateSetに書き出し、読み込み
void operator<<=(StateManager& man, const RTMEUS::StateSet &states)
{
    man.copyFromStateSet(states);
}
void operator>>=(StateManager& man, RTMEUS::StateSet &states)
{
    man.copyToStateSet(states);
}
